# -*- coding: utf-8 -*-
import base64
import hashlib
import json
import random

import requests
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from Crypto.Hash import SHA
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5

from common.utils import track_logging

_LOGGER = track_logging.getLogger(__name__)

_GATEWAY = 'https://www.albpay.cn/webservice/hello?wsdl'

APP_CONF = {
    '100004182297': {
    },
}


def _get_api_key(mch_id):
    return APP_CONF[mch_id]['API_KEY']


def _get_pid(mch_id):
    return APP_CONF[mch_id]['pid']


_pub_key_str = """-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALheeE2Ag/JjgibepJXHxy6KXUxXTa/qeadb87lFQUUwIzhSrER6xn7Zw4w9um06rEegWbuboOSup5ftqP2QanMCAwEAAQ==
-----END PUBLIC KEY-----"""

_my_private_key = """-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAuF54TYCD8mOCJt6klcfHLopdTFdNr+p5p1vzuUVBRTAjOFKsRHrGftnDjD26bTqsR6BZu5ug5K6nl+2o/ZBqcwIDAQABAkAH8RHPjNSiMUUe9YIzbXqX95/TNQOEq134Jo7WETShjUFTMLx5oXPmcJV2vzKipgoLeTje/3VCt0A4H4Gmb6lhAiEA/qHD1HSK5yj9jsbnTzMrGllj7fAoOWP77H6OE4lrtQMCIQC5XA+8HtadPJsx1seOsrMZum5yfEENKoCWs3hFNC7h0QIhAOipEnBL1KeG8rfE0pGxZU78IqzEZVybGRNsR5FeXUXVAiBAHXz/2DbqCoWwFpfOXzeeRaNgjGQ/9pymBAws++DfkQIhAOUOnSvfO0renb40+DM4d9QSdc1G5FlecdaMiCUWn+0G
-----END ENCRYPTED PRIVATE KEY-----"""


def rsa_long_encrypt(pub_key_str, msg, length=100):
    """
    单次加密串的长度最大为 (key_size/8)-11
    1024bit的证书用100， 2048bit的证书用 200
    """
    pubobj = RSA.importKey(pub_key_str)
    pubobj = Cipher_pkcs1_v1_5.new(pubobj)
    res = []
    for i in range(0, len(msg), length):
        res.append(pubobj.encrypt(msg[i:i + length]))
    return "".join(res)


def rsa_long_decrypt(priv_key_str, msg, length=128):
    """
    1024bit的证书用128，2048bit证书用256位
    """
    privobj = RSA.importKey(priv_key_str, passphrase='614360')
    privobj = Cipher_pkcs1_v1_5.new(privobj)
    res = []
    for i in range(0, len(msg), length):
        res.append(privobj.decrypt(msg[i:i + length], 'xyz'))
    return "".join(res)


def _gen_sign(message):
    key = RSA.importKey(_my_private_key)
    h = SHA.new(message)
    signer = Signature_pkcs1_v1_5.new(key)
    signature = signer.sign(h)
    return base64.b64encode(signature)


def _verify_sign(data, signature, key):
    key = RSA.importKey(key)
    h = SHA.new(data)
    verifier = Signature_pkcs1_v1_5.new(key)
    if verifier.verify(h, base64.b64decode(signature)):
        return True
    return False


def _verify_sign1(data, signature, key):
    key = RSA.importKey(key)
    digetst = SHA.new()
    digetst.update(data.encode('utf8'))
    verifier = Signature_pkcs1_v1_5.new(key)
    if verifier.verify(digetst, bytes(signature, 'utf-8')):
        return True
    return False


def generate_rsa_sign_str(parameter):
    s = ''
    for k in sorted(parameter.keys()):
        s += '%s=%s&' % (k.encode('utf8'), parameter[k].encode('utf8'))
    return s[0:len(s) - 1]


def _get_device_ip(info):
    try:
        extra = json.loads(info['extra'])
    except:
        extra = {}
    user_info = extra.get('user_info', {})
    return user_info.get('device_ip') or '127.0.0.1'


# 支付宝	zfb
# 微信	wx
def _get_pay_type(service):
    if service == 'wxpay':
        return 'wx'
    else:
        return 'zfb'


def _fix_pay_amount(pay, pay_amount):
    extend = json.loads(pay.extend or '{}')
    if pay_amount >= 10 and int(pay_amount) == pay_amount:
        discount = random.randint(1, 10)
        pay_amount = pay_amount - float(discount) / 100
        extend.update({'discount': str(float(discount) / 100)})
        order_db.fill_extend(pay.id, extend)
    return pay_amount


def create_charge(pay, pay_amount, info):
    ''' 创建订单 '''
    pay_amount = _fix_pay_amount(pay, pay_amount)
    app_id = info['app_id']
    api_key = _get_api_key(app_id)
    service = info.get('service')

    post_data = {
        'companyid': app_id,
        'outTradeNo': str(pay.id),
        'body': 'charge',
        'subject': 'charge',
        'totalAmoun': str(pay_amount),
        'paymode': _get_pay_type(service),
        'payer': 'lilei',
        'domain': 'www.bmysa.top',
        'notify_url': '{}/pay/api/{}/yishoupay/{}'.format(settings.NOTIFY_PREFIX, settings.NOTIFY_PATH, app_id),
    }

    sign = _gen_sign(j + api_key)
    url = _GATEWAY.format(get_data['method'], get_data['pid'], get_data['randstr'], sign, get_data['timestamp'])
    j_p = json.dumps(post_data, sort_keys=True, separators=(',', ':'))
    d = rsa_long_encrypt(_pub_key_str, j_p, 117)
    b = base64.b64encode(d)
    _LOGGER.info("yishoupay create  url: %s, data: %s", url, post_data)
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    response = requests.post(url, data='data=' + b, headers=headers, timeout=3)
    _LOGGER.info("yishoupay create rdp data: %s", response.text)
    rsp_obj = json.loads(response.text)
    return {'charge_info': rsp_obj['data']['out_pay_url']}


def generate_sign(parameter, key):
    s = ''
    for k in sorted(parameter.keys()):
        if parameter[k] != '' and parameter[k] != None:
            s += '%s=%s&' % (k, parameter[k])
    s += 'key=%s' % key
    m = hashlib.md5()
    m.update(s.encode('utf8'))
    sign = m.hexdigest().lower()
    return sign


def verify_notify_sign(params, key):
    sign = params['sign']
    params.pop('sign')
    calculated_sign = generate_sign(params, key)
    if sign != calculated_sign:
        _LOGGER.info("yishoupay sign: %s, calculated sign: %s", sign, calculated_sign)
        raise ParamError('sign not pass, data: %s' % params)


# SUCCEED
def check_notify_sign(request, app_id):
    api_key = _get_api_key(app_id)
    data = dict(request.POST.iteritems())
    _LOGGER.info("yishoupay notify data: %s", data)
    verify_notify_sign(data, api_key)
    pay_id = data['out_trade_no']
    if not pay_id:
        _LOGGER.error("fatal error, out_trade_no not exists, data: %s" % data)
        raise ParamError('yishoupay event does not contain pay ID')

    pay = order_db.get_pay(int(pay_id))
    if not pay:
        raise ParamError('pay_id: %s invalid' % pay_id)
    if pay.status != PAY_STATUS.READY:
        raise ParamError('pay %s has been processed' % pay_id)

    mch_id = pay.mch_id
    trade_status = data[u'trade_result']
    trade_no = data[u'trade_no']
    total_fee = float(data[u'trade_amount']) / 100.0
    discount = float(json.loads(pay.extend or '{}').get('discount', 0))
    extend = {
        'discount': discount,
        'trade_status': trade_status,
        'trade_no': trade_no,
        'total_fee': total_fee
    }

    from common.channel.pay import check_channel_order
    check_channel_order(pay_id, total_fee, app_id)

    if trade_status == 'SUCCESS':
        _LOGGER.info('yishoupay check order success, mch_id:%s pay_id:%s' % (mch_id, pay_id))
        order_db.add_pay_success(mch_id, pay_id, total_fee, trade_no, extend)
        # async notify
        async_job.notify_mch(pay_id)


def query_charge(order_id, trade_no=None):
    ''' 查询订单 '''
    # prepare param
    pass


def generate_sign_str(parameter):
    '''  生成下单签名 '''
    s = ''
    for k in parameter.keys():
        if parameter[k] != None:
            s += '%s=%s&' % (k, parameter[k])
    return s[0:len(s) - 1]


if __name__ == '__main__':
    app_id = '100004182297'
    service = 'wxpay'
    pay_amount = 1.23

    post_data = {
        'companyid': app_id,
        'outTradeNo': '1223123123',
        'body': 'charge',
        'subject': 'charge',
        'totalAmoun': str(pay_amount),
        'paymode': _get_pay_type(service),
        'payer': 'lilei',
        'domain': 'www.bmysa.top',
        'notify_url': 'http://www.qq.com/',
    }
    s = generate_sign_str(post_data)
    post_data['sign'] = _gen_sign(s)
    print post_data
    j = json.dumps(post_data)
    print j
    headers = {'Content-Type': 'text/html;charset=utf-8'}
    # headers = {'Content-type': 'application/json'}
    response = requests.post(_GATEWAY, data=j, headers=headers, timeout=3)
    print response.status_code
    print response.text
    print response.url
